﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;

namespace UnitOfWorkCore.Domain.Abstractions
{
    /// <summary>
    /// 值对象（Value Object）的抽象基类
    /// 值对象是没有唯一标识符的领域对象，其相等性由所有属性值共同决定。
    /// 典型应用场景：地址、货币、颜色等可互换且无独立生命周期概念的领域模型。
    /// </summary>
    public abstract class ValueObject
    {
        /// <summary>
        /// 相等性比较运算符的实现
        /// 处理 null 值场景并委托给 Equals 方法
        /// </summary>
        /// <param name="left">左操作数</param>
        /// <param name="right">右操作数</param>
        /// <returns>
        /// true: 两者都为 null 或属性值完全一致
        /// false: 单个为 null 或属性值存在差异
        /// </returns>
        protected static bool EqualOperator(ValueObject left, ValueObject right)
        {
            // 使用异或处理单个 null 的情况（一个 null 另一个非 null）
            if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null))
            {
                return false;
            }
            // 两者都为 null 或通过 Equals 比较值
            return ReferenceEquals(left, null) || left.Equals(right);
        }

        /// <summary>
        /// 不等运算符的简单取反实现
        /// </summary>
        protected static bool NotEqualOperator(ValueObject left, ValueObject right)
        {
            return !EqualOperator(left, right);
        }

        /// <summary>
        /// 抽象方法 - 获取原子属性值集合
        /// 子类必须实现此方法，返回所有参与相等性比较的属性值
        /// 注意：属性顺序必须固定，影响相等性判断结果
        /// </summary>
        /// <example>
        /// protected override IEnumerable<object> GetAtomicValues()
        /// {
        ///     yield return Street;
        ///     yield return City;
        ///     yield return ZipCode;
        /// }
        /// </example>
        protected abstract IEnumerable<object> GetAtomicValues();


        //var address1 = new Address("北京", "朝阳区", "建国路");
        //var address2 = new Address("北京", "朝阳区", "建国路");

        //var addressSet = new HashSet<Address>();
        //addressSet.Add(address1);
        //addressSet.Add(address2);

        //Console.WriteLine(addressSet.Count); // 输出 1（自动去重！）
        //HashSet 的去重能力依赖于对象的 GetHashCode 和 Equals 方法。
        //重写对象的Equals和GetHashCode方法，每个对象都有Equals和GetHashCode方法，因为对象都继承object

        /// <summary>
        /// 重写对象相等性比较
        /// 执行严格类型检查后，逐个比较原子属性值
        /// </summary>
        public override bool Equals(object obj)
        {
            // 类型检查：null 或类型不匹配直接返回 false
            if (obj == null || obj.GetType() != GetType())
            {
                return false;
            }

            // 类型转换后获取原子值迭代器
            ValueObject other = (ValueObject)obj;
            IEnumerator<object> thisValues = GetAtomicValues().GetEnumerator();
            IEnumerator<object> otherValues = other.GetAtomicValues().GetEnumerator();

            // 同步遍历比较每个原子值
            while (thisValues.MoveNext() && otherValues.MoveNext())
            {
                // 处理单个 null 的情况（异或逻辑）
                if (ReferenceEquals(thisValues.Current, null) ^ ReferenceEquals(otherValues.Current, null))
                {
                    return false;
                }

                // 非 null 值调用 Equals 比较
                if (thisValues.Current != null && !thisValues.Current.Equals(otherValues.Current))
                {
                    return false;
                }
            }

            // 最终检查属性数量是否一致
            return !thisValues.MoveNext() && !otherValues.MoveNext();
        }

        /// <summary>
        /// 计算哈希码
        /// 基于所有原子属性值的哈希码组合（异或操作）
        /// 注意：子类属性顺序变化会影响哈希码
        /// </summary>
        public override int GetHashCode()
        {
            return GetAtomicValues()
                .Select(x => x != null ? x.GetHashCode() : 0)
                .Aggregate((x, y) => x ^ y); // 异或组合哈希
        }
    }
}
